package edu.uoc.tdp.servidor.bbdd.proves;


import edu.uoc.tdp.beans.proves.Prova;
import edu.uoc.tdp.beans.proves.EstatProva;
import edu.uoc.tdp.common.EOlympicsException;
import edu.uoc.tdp.common.EOlympicsExceptionProva;
import edu.uoc.tdp.bbdd.GestorDiscConnexio;
import java.sql.Connection;
import java.util.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;


/**
 * Classe GestorProva
 * TDP Grup 1X4J
 */

//TODO NOTES XMARTI
/* Fet i provat:
 * - Inserir nova prova
 * 
 * - recuperar proves (edicio, inscripcio, realitzacio eliminatoria, realitzacio
 *   final, tancades i cancelades)
 * - recuperar una prova a partir del seu identificador.
 * Falta fer:
 * - implementar l'auditoria
 * - MODIFICAR PROVA HI HA UN ERROR A GETESTAT(), DEMA SERÀ UN ALTRA DIA
 */
public class GestorProva {
    
    private GestorDiscConnexio gestor;
    private Connection connexio;

    /**
     * Constructor de la classe Gestora
     * Crea un nou gestor de disc.
     */
    public GestorProva() throws EOlympicsException {
        this.gestor = new GestorDiscConnexio();
        this.gestor.obreConnexioBD();
        this.connexio = gestor.getConnexio();
    }

    /**
     * Constructor de la classe Gestora
     * Utilitza el gestor de disc passat com a paràmetre
     * @param gdc connexió a la BD de tipus GestorDiscConnexio
     */
    public GestorProva(GestorDiscConnexio gdc) {
        this.gestor   = gdc;
        this.connexio = gdc.getConnexio();
    }
    
    
    
   
    /**
     * Accessor de lectura, recupera totes les proves en periode d'edicio
     * @return Llista de proves
     * @throws EOlympicsException   
     */
   
    public List<Prova> getProvesEdicio() throws EOlympicsException{        
        Date avui= new Date(System.currentTimeMillis());        
        String sql="SELECT P.idProva,P.descripcio,P.dataIniInscripcio,P.dataFiInscripcio,P.nombrePlaces "
                + "FROM PROVA P "                
                + "WHERE P.dataIniInscripcio>='"+ avui +"' "
                + "AND P.estat<> '"  +EstatProva.TANCADA.getEstat() +"' "
                + "AND P.estat<>'"  +EstatProva.CANCELADA.getEstat() +"' ";
                                
        return getProves(sql);
    }
    /**
     * Accessor de lectura, recupera totes les proves en periode d'inscripcio
     * @return Llista de proves
     * @throws EOlympicsException 
     */
    public List<Prova> getProvesInscripcio() throws EOlympicsException{        
        Date avui= new Date(System.currentTimeMillis());        
        String sql="SELECT P.idProva,P.descripcio,P.dataIniInscripcio,P.dataFiInscripcio,P.nombrePlaces "
                + "FROM PROVA P "                
                + "WHERE P.dataIniInscripcio<='"+ avui +"' "
                + "AND P.dataFiInscripcio>='"+ avui +"' "
                + "AND P.estat<> '"  +EstatProva.TANCADA.getEstat() +"' "
                + "AND P.estat<>'"  +EstatProva.CANCELADA.getEstat() +"' ";
        
        return getProves(sql);
    }
    /**
     * Accessor de lectura, recupera totes les proves en periode de realització Eliminatoria
     * @return Llista de proves
     * @throws EOlympicsException 
     */
    public List<Prova> getProvesEliminatories() throws EOlympicsException{        
        Date avui= new Date(System.currentTimeMillis());        
        String sql="SELECT P.idProva,P.descripcio,P.dataIniInscripcio,P.dataFiInscripcio,P.nombrePlaces "
                + "FROM PROVA P,RONDA R "                
                + "WHERE P.idProva = R.idProva "
                + "AND R.tipusRonda = 'E' "
                + "AND R.dataIniciRealitzacio<='"+avui+"' "
                + "AND R.dataFiRealitzacio >='"+avui+"' "                
                + "AND P.estat<> '"  +EstatProva.TANCADA.getEstat() +"' "
                + "AND P.estat<>'"  +EstatProva.CANCELADA.getEstat() +"' ";
        
        return getProves(sql);
    }
    /**
     * Accessor de lectura, recupera totes les proves en periode de realització Final
     * @return Llista de proves
     * @throws EOlympicsException 
     */
    public List<Prova> getProvesFinals() throws EOlympicsException{        
        Date avui= new Date(System.currentTimeMillis());        
        String sql="SELECT P.idProva,P.descripcio,P.dataIniInscripcio,P.dataFiInscripcio,P.nombrePlaces "
                + "FROM PROVA P,RONDA R "                
                + "WHERE P.idProva = R.idProva "
                + "AND R.tipusRonda = 'F' "
                + "AND R.dataIniciRealitzacio<='"+avui+"' "
                + "AND R.dataFiRealitzacio >='"+avui+"' "                
                + "AND P.estat<> '"  +EstatProva.TANCADA.getEstat() +"' "
                + "AND P.estat<>'"  +EstatProva.CANCELADA.getEstat() +"' ";
                                
        return getProves(sql);
    }
    /**
     * Accessor de lectura, recupera totes les proves en estat TANCADA
     * @return LLista de proves
     * @throws EOlympicsException 
     */
    public List<Prova> getProvesTancades() throws EOlympicsException{                
        String sql="SELECT P.idProva,P.descripcio,P.dataIniInscripcio,P.dataFiInscripcio,P.nombrePlaces "
                + "FROM PROVA P "                
                + "WHERE P.estat = '"  +EstatProva.TANCADA.getEstat() +"'";
        return getProves(sql);
    }
    /**
     * Accessor de Lectura,recupera totes les proves en estat CANCELADA
     * @return LLista de proves
     * @throws EOlympicsException 
     */
    public List<Prova> getProvesCancelades() throws EOlympicsException{                
        String sql="SELECT P.idProva,P.descripcio,P.dataIniInscripcio,P.dataFiInscripcio,P.nombrePlaces "
                + "FROM PROVA P "                
                + "WHERE P.estat = '"  +EstatProva.CANCELADA.getEstat() +"'";
        return getProves(sql);
    }
    /**
     * Recupera una llista de proves
     * @param sql                       Setència SQL per recuperar les proves
     * @return  Una llista deproves
     * @throws EOlympicsException 
     */
    private List<Prova> getProves(String sql) throws EOlympicsException{
        List <Prova>proves= new ArrayList<Prova>();
        Statement st=gestor.creaSentencia();
        
        try{
            ResultSet rs=st.executeQuery(sql);
            while (rs.next()){                                
                proves.add(new Prova(rs.getInt(1),rs.getString(2),rs.getDate(3),rs.getDate(4),rs.getInt(5)));
            }
            st.close();
            rs.close();
        }catch (SQLException sqle){
            treatExceptionSQL(sqle.getMessage());
            
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
        }                        
        return proves;
        
    }
    
    /**
     * Accessor de lectura, recupera una prova a partir del seu identificador.
     * @param idProva               Identificador de la prova.
     * @return  Prova
     * @throws EOlympicsException 
     */
    public Prova getProva(Integer idProva) throws EOlympicsException{
        Prova prova = null;
        Statement st=gestor.creaSentencia();
        String sql="SELECT P.idProva,P.descripcio,p.dataIniInscripcio,P.dataFiInscripcio,P.nombrePlaces, P.estat "
                + "FROM PROVA P "                
                + "WHERE P.idProva="+ idProva ;
        try{
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                
    
                if(rs.getString(6).equals("null")){
                  prova=(new Prova(rs.getInt(1),rs.getString(2),rs.getDate(3),rs.getDate(4),rs.getInt(5)));
                }
                else{
                    prova=(new Prova(rs.getInt(1),rs.getString(2),rs.getDate(3),rs.getDate(4),rs.getInt(5),EstatProva.valueOf(rs.getString(6))));
                }
                
            }
            st.close();
            rs.close();
        }catch (SQLException sqle){
            System.out.println(sqle.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_SQL);
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
        }
        
        return prova;
    }
    
    /**
     * Accessor d'escriptura, Insereix una nova proba a la BBDD.
     * @param prova                 Prova a inserir.
     * @return idProva              Identificador de la prova inserida. 
     * @throws EOlympicsException 
     */
    private Integer setAltaProva(Prova prova) throws EOlympicsException{
        
        Integer idProva=0;
        Statement st=gestor.creaSentencia();
        
        
        String sql="INSERT INTO PROVA "
                + "(descripcio,dataIniInscripcio,dataFiInscripcio,nombrePlaces,estat) "
                + "VALUES('"+prova.getDescripcio() + "','"
                + new java.sql.Date(prova.getDataIniInscripcio().getTime())+ "','"
                + new java.sql.Date(prova.getDataFiInscripcio().getTime())+ "',"
                + prova.getNombrePlaces()+ ",'"
                + prova.getEstat()+"') "                
                + "RETURNING idProva";
               
       try{
            ResultSet rs=st.executeQuery(sql); 
           if(rs.next()){
               idProva=rs.getInt(1);
           }
            rs.close();            
            //aqui ja ens cal anar per afegir les rondes
            
       }catch(SQLException sqle){
           //System.out.println(sqle.getMessage());
           treatExceptionSQL(sqle.getMessage());
                                       
       }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
       }
        
        return idProva;
    }
    
    /**
     * Acessor d'escriptura, modifica les dades d'una prova
     * @param prova                 prova que cal modificar
     * @return operacions           Nombre de proves modificades 
     * @throws EOlympicsException 
     */
    private int setModificarProva(Prova prova) throws EOlympicsException{
        Integer operacions=0;
        Integer idProva=prova.getIdProva();
        Statement st=gestor.creaSentencia();
        String sql="UPDATE PROVA "
                + "SET descripcio=?,dataIniInscripcio=?,dataFiInscripcio=?,nombrePlaces=?,estat=? "
                + "WHERE idProva=?";
       PreparedStatement ps = gestor.crearPreparedStatement(sql);
       
       try{
           ps.setString(1, prova.getDescripcio());
           //ps.setDate(2, prova.getDataIniInscripcio());
           //ps.setDate(3, prova.getDataFiInscripcio());
           ps.setDate(2, new java.sql.Date(prova.getDataIniInscripcio().getTime()));
           ps.setDate(3, new java.sql.Date(prova.getDataFiInscripcio().getTime()));
           
           ps.setInt(4, prova.getNombrePlaces());
           ps.setString(5, prova.getEstat());
           ps.setInt(6, prova.getIdProva());
           operacions=ps.executeUpdate();
           ps.close();
           if(operacions==0){
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL);
           }
       }catch(SQLException sqle){
            treatExceptionSQL(sqle.getMessage());
       }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
       }
        return idProva;
    }
    public int guardarProva(Prova prova) throws EOlympicsException{
        Integer idProva;
        if(!existeixProva(prova.getIdProva())){
            idProva=setAltaProva(prova);
        } 
        else
        {
            idProva=setModificarProva(prova);
        }
        return idProva;
    }
    private boolean existeixProva(Integer idProva)throws  EOlympicsException{
        boolean existeix=false;
        Statement st=gestor.creaSentencia();
        String sql="SELECT P.idProva "
                + "FROM PROVA P "                
                + "WHERE P.idProva="+ idProva ;        
        
        try {
        ResultSet rs = st.executeQuery(sql);
            if (rs.next())existeix=true;
            st.close();
            rs.close();
        } catch (SQLException ex) {
            treatExceptionSQL(ex.getMessage());
        }
            
            return existeix;
    }
    
    /**
     * Tracta les excepcions SQL, diferenciant-les pel missatge de l'error
     * @param sqle                      ERROR.message()
     * @throws EOlympicsExceptionProva
     * @throws EOlympicsException 
     */
    private void treatExceptionSQL(String sqle) throws EOlympicsExceptionProva, EOlympicsException{
           if(sqle.contains("pk_prova")) {
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL_PK_PROVA);
           }else if(sqle.contains("ck_datainsc")) {
               throw new EOlympicsExceptionProva(EOlympicsExceptionProva.ERR_SQL_CK_PROVA);           
           }
           else{
               System.out.println(sqle);
               throw new EOlympicsException(EOlympicsException.ERR_SQL);
           }
        
    }
    
    
    
    
}
